/*
 * line_search.h
 *
 *  Created on: Jun 3, 2011
 *      Author: tqlong
 */

#ifndef LINE_SEARCH_H_
#define LINE_SEARCH_H_

template<typename Function>
  class LineSearch
  {
  public:
    typedef Function func_type;
    typedef typename Function::range_type range_type;
    typedef typename Function::domain_type domain_type;
  public:
    LineSearch(func_type &f, const domain_type &x0, domain_type &x,
        range_type f0, const domain_type& grad, const domain_type& dir, double step) :
      f_(f), x0_(x0), x_(&x), f0_(f0), grad_(grad), dir_(dir), step_(step)
    {
      if (!f.has_value_)
        {
          std::cerr << "Function needs to produce value() at " << __FILE__
              << ":" << __LINE__ << std::endl;
          exit(1);
        }
    }

    bool
    search()
    {
      double rate = arma::dot(grad_, dir_);
      step_ *= 2.0;
      do
        {
          step_ *= 0.5;
          *x_ = x0_ + step_ * dir_;
          fx_ = f_.value(*x_);
        }
      while (fx_ > f0_ + 0.5 * step_ * rate && step_ >= 1e-10);

      if (step_ < 1e-10)  // step is too small, stop line search
        {
          step_ = 0;
          *x_ = x0_;
          fx_ = f0_;
          return false;   // failure
        }
      else
        {
          return true;
        }
    }

    double
    step() const
    {
      return step_;
    }

    range_type
    fx() const
    {
      return fx_;
    }
  protected:
    func_type &f_;
    const domain_type &x0_;
    domain_type *x_;
    range_type f0_, fx_;
    const domain_type &grad_;
    const domain_type &dir_;
    double step_;
  };

#endif /* LINE_SEARCH_H_ */
